#ifndef _EXTENDED_LIB_PARSER_H
#define _EXTENDED_LIB_PARSER_H

//#define DEBUG

#include <map>
#include <cassert>
#include <limits>
#include <string>
#include <fstream>
#include <utility>
#include <algorithm>


// Boost Library Headers

#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/utility.hpp>

#include "parser_helper.h"

typedef std::map< std::string, double> tableVal ;
/*
  struct UnifiedLUT {

  std::vector<double> loadIndices ;
  std::vector<double> transitionIndices ;
  std::vector<vector<tableVal> > vectorVal ;
	
  double operator() (double outCap, double inpTrans, bool& valid, std::string cellName)
  {
  int capIndex = 0 ;
  int transIndex = 0;
		
  bool validCap = false ;
  bool validTrans = false ;
		
  for (int i = 0 ; i < (int)this->loadIndices.size() ; ++i)
  {
  if (outCap > this->loadIndices[i])
  continue ;
			
  capIndex = i ;
  validCap = true ;
  break ;
  }
		
		
  for (int j = 0 ; j < (int)this->transitionIndices.size(); ++j)
  {
  if (inpTrans > this->transitionIndices[j])
  continue ;
				
  transIndex = j ;
  validTrans = true ;
  break ;
  }
		
		
  if (!validTrans || !validCap)
  {
  valid = false ;
  return 0.0 ;
  }
		
  bool isCellValid = false ;
  if (vectorVal[capIndex][transIndex].find(cellName) != vectorVal[capIndex][transIndex].end())
  {
  isCellValid = true ;
  }	

  if (!isCellValid)
  {
  valid = false ;
  return 0.0 ;
  }
		
  double Wx, Wy ;
		
  valid = true ;
		
  if (outCap == this->loadIndices[0])
  capIndex = 1 ;
  if (inpTrans == this->transitionIndices[0])
  transIndex = 1;
  	
  Wx = (double)(outCap - this->loadIndices[capIndex - 1]) / 
  (double) (this->loadIndices[capIndex] - this->loadIndices[capIndex-1]) ;
  						
  Wy = (double)(inpTrans - this->transitionIndices[transIndex-1]) / 
  (double) (this->transitionIndices[transIndex] - this->transitionIndices[transIndex-1]) ;
						
						
  double part1 = (1 - Wx) * (1 - Wy) * this->vectorVal[capIndex-1][transIndex-1][cellName] ;
  double part2 = (Wx) * (1 - Wy) * this->vectorVal[capIndex][transIndex-1][cellName] ; 
  double part3 = (1 - Wx) * Wy * this->vectorVal[capIndex-1][transIndex][cellName] ;
  double part4 = Wx * Wy * this->vectorVal[capIndex][transIndex][cellName] ;
  	
  return ( part1 + part2 + part3 + part4 ) ;
		
		
  }

  } ;*/


class CircuitGraph ;
class ExtendedLibParser:public LibParser
{
  public:
        // Constructor
        ExtendedLibParser (std::string fileName) : LibParser(fileName) {}
	
        // Read the cells from library file
        int readStandardLibraryCell () ;
		
        // Returns the item in standard library cell
        inline LibParserCellInfo getStandardCell (std::string);
		
        double getMinInputCapacitance ( std::string footprint, std::string pinName);
                        
        // Fill the second argument with the cell which has the same footprint specified by first argument
        void findSameFootPrint(std::string, std::vector<std::string>&) ;
		
        // Returns the max and min capacitance of a pin in the range of same footprint
        std::pair<double, double> pinCapacitance (std::string, std::string) ;
		
        // Store the valid combinations in terms of max output capacitance in 
        // the filename specified by first argument
        void findCombinations(std::string, double) ;
		
		
        // Find the output capacitance range of a footprint
        void findCapRange (std::string, vector<double>&) ;
		
        // Find the input transition of a footprint
        void findTransRange (std::string, vector<double>&) ;

        // Make the template unified library		
        // Returns the max output capacitance of a cell
        double findMaxOutputCapacitance (std::string) ;
		
        // Find the max delay of a gate, given the input transition for each pin and output capacitance
        double maxRiseDelay (std::string, std::map<std::string, double>&, double, bool&) ;
        double maxFallDelay (std::string, std::map<std::string, double>&, double, bool&) ;
		
		
        double getInputCapacitance(std::string, std::string) ;	
		
        // Find the max transition of a gate, given the input transition for each pin and output capacitance
        double maxRiseTransition (std::string, std::map<std::string, double>&, double, bool&) ;
        double maxFallTransition (std::string, std::map<std::string, double>&, double, bool&) ;
		
        // Find the max average delay of a gate 
        double findMaxAvgDelay(std::string) ;
		
        // Whether the first cell has lower delay and (lower or equal) leakage power 
        bool isCover (std::string, std::string, int) ;

        // Prunes out the gates which have higher delay and higher leakage in comparison to others
        void pruneFootprint(std::string, std::vector<std::string>&) ;
		
        void drawDelayLeakageCurve (std::string) ;
                
        void deltaCapDelay(std::string, std::string) ;
		
        double default_max_transition;
                
        void intermediateCapPoints(LibParserLUT&, std::ofstream&, double, double, std::vector<double>&) ;
        std::map <std::string, LibParserCellInfo> mapStandardLibraryCells ;
		
        double maxTransition ;
		
  private:
        // Fill last argument with valid cells in terms of max output capacitance
        // second argument: cell name
        // first argument: max output capacitance
        void findLegalCombination (double, std::string, std::vector<std::string>&) ;
        void extractAllFootPrints (std::vector<std::string>&) ;
};

#endif
